package com.base.core.utils;

import com.base.core.enums.SystemCodeEnum;
import com.base.core.exception.ServiceException;
import com.base.core.result.ResponseCodeEnum;
import io.swagger.annotations.ApiModel;
import org.springframework.lang.Nullable;

import java.io.Serializable;
import java.util.Optional;

/**
 * 统一授权响应类
 *
 * @author becker
 * @since 0.0.1
 */
@ApiModel(description = "返回信息")
public class R<T> implements Serializable {
    /**
     * 授权响应状态码
     */
    private Integer code;

    /**
     * 授权响应信息
     */
    private String msg;

    /**
     * 是否成功
     */
    private boolean success;

    /**
     * 授权响应数据，当且仅当 code = 2000 时返回
     */
    private T data;

    private R(ResponseCodeEnum responseCode) {
        this(responseCode, responseCode.getMessage(), null);
    }

    private R(ResponseCodeEnum responseCode, String msg) {
        this(responseCode, msg, null);
    }

    private R(ResponseCodeEnum responseCode, T data) {
        this(responseCode, responseCode.getMessage(), data);
    }

    private R(ResponseCodeEnum responseCode, String msg, T data) {
        this.code = responseCode.getCode();
        this.msg = msg;
        this.data = data;
        this.success = SystemCodeEnum.SUCCESS == responseCode;
    }

    private R(Integer responseCode, String msg) {
        this(responseCode, msg, null);
    }

    private R(Integer responseCode, String msg, T data) {
        this.code = responseCode;
        this.msg = msg;
        this.data = data;
        this.success = SystemCodeEnum.SUCCESS.getCode() == responseCode;
    }

    public R() {}

    /**
     * 判断返回是否为成功
     *
     * @param result Result
     * @return 是否成功
     */
    public static boolean isSuccess(@Nullable R<?> result) {
        return Optional.ofNullable(result)
                .map(r -> r.code)
                .map(code -> SystemCodeEnum.SUCCESS.getCode() == code)
                .orElse(Boolean.FALSE);
    }

    /**
     * 判断返回是否为成功
     *
     * @param result Result
     * @return 是否成功
     */
    public static boolean isFail(@Nullable R<?> result) {
        return !R.isSuccess(result);
    }

    /**
     * 获取data
     *
     * @param result Result
     * @param <T>    泛型标记
     * @return 泛型对象
     */
    @Nullable
    public static <T> T getData(@Nullable R<T> result) {
        return Optional.ofNullable(result)
                .filter(r -> r.success)
                .map(x -> x.data)
                .orElse(null);
    }

    /**
     * 返回成功
     *
     * @param <T> 泛型标记
     * @return Result
     */
    public static <T> R<T> success() {
        return new R<>(SystemCodeEnum.SUCCESS);
    }

    /**
     * 成功-携带数据
     *
     * @param data 数据
     * @param <T>  泛型标记
     * @return Result
     */
    public static <T> R<T> success(@Nullable T data) {
        return new R<>(SystemCodeEnum.SUCCESS, data);
    }

    /**
     * 根据状态返回成功或者失败
     *
     * @param status 状态
     * @param msg    异常msg
     * @param <T>    泛型标记
     * @return Result
     */
    public static <T> R<T> status(boolean status, String msg) {
        return status ? R.success() : R.fail(msg);
    }

    /**
     * 根据状态返回成功或者失败
     *
     * @param status 状态
     * @param sCode  异常code码
     * @param <T>    泛型标记
     * @return Result
     */
    public static <T> R<T> status(boolean status, ResponseCodeEnum sCode) {
        return status ? R.success() : R.fail(sCode);
    }

    /**
     * 返回失败信息，用于 web
     *
     * @param msg 失败信息
     * @param <T> 泛型标记
     * @return {Result}
     */
    public static <T> R<T> fail(String msg) {
        return new R<>(SystemCodeEnum.FAILURE, msg);
    }

    /**
     * 返回失败信息，用于 web
     *
     * @param <T> 泛型标记
     * @return {Result}
     */
    public static <T> R<T> fail() {
        return new R<>(SystemCodeEnum.FAILURE);
    }

    /**
     * 返回失败信息
     *
     * @param rCode 异常枚举
     * @param <T>   泛型标记
     * @return {Result}
     */
    public static <T> R<T> fail(ResponseCodeEnum rCode) {
        return new R<>(rCode);
    }

    /**
     * 返回失败信息
     *
     * @param rCode 异常枚举
     * @param msg   失败信息
     * @param <T>   泛型标记
     * @return {Result}
     */
    public static <T> R<T> fail(ResponseCodeEnum rCode, String msg) {
        return new R<>(rCode, msg);
    }

    /**
     * 返回失败信息
     *
     * @param rCode 异常枚举
     * @param msg   失败信息
     * @param <T>   泛型标记
     * @return {Result}
     */
    public static <T> R<T> fail(ResponseCodeEnum rCode, String msg, T data) {
        return new R<>(rCode, msg, data);
    }

    public static <T> R<T> fail(Integer rCode, String msg) {
        return new R<>(rCode, msg);
    }

    public static <T> R<T> fail(Integer rCode, String msg, T data) {
        return new R<>(rCode, msg, data);
    }

    /**
     * 当 result 不成功时：直接抛出失败异常，返回传入的 result。
     *
     * @param result R
     */
    public static void throwOnFail(R<?> result) {
        if (R.isFail(result)) {
            throw new ServiceException(result);
        }
    }

    /**
     * 当 result 不成功时：直接抛出失败异常，返回传入的 rCode
     *
     * @param result R
     * @param rCode  异常枚举
     */
    public static void throwOnFail(R<?> result, ResponseCodeEnum rCode) {
        if (R.isFail(result)) {
            throw new ServiceException(rCode);
        }
    }

    /**
     * 当 result 不成功时：直接抛出失败异常，返回传入的 rCode、message
     *
     * @param result R
     * @param rCode  异常枚举
     * @param msg    失败信息
     */
    public static void throwOnFail(R<?> result, ResponseCodeEnum rCode, String msg) {
        if (R.isFail(result)) {
            throw new ServiceException(rCode, msg);
        }
    }

    /**
     * 当 status 不为 true 时：直接抛出失败异常 rCode
     *
     * @param status status
     * @param rCode  异常枚举
     */
    public static void throwOnFalse(boolean status, ResponseCodeEnum rCode) {
        if (!status) {
            throw new ServiceException(rCode);
        }
    }

    /**
     * 当 status 不为 true 时：直接抛出失败异常 rCode、message
     *
     * @param status status
     * @param rCode  异常枚举
     * @param msg    失败信息
     */
    public static void throwOnFalse(boolean status, ResponseCodeEnum rCode, String msg) {
        if (!status) {
            throw new ServiceException(rCode, msg);
        }
    }

    /**
     * 直接抛出失败异常，抛出 code 码
     *
     * @param rCode IResultCode
     */
    public static void throwFail(ResponseCodeEnum rCode) {
        throw new ServiceException(rCode);
    }

    /**
     * 直接抛出失败异常，抛出 code 码
     *
     * @param rCode   IResultCode
     * @param message 自定义消息
     */
    public static void throwFail(ResponseCodeEnum rCode, String message) {
        throw new ServiceException(rCode, message);
    }

    /**
     * 直接抛出失败异常，抛出 code 码
     *
     * @param rCode   IResultCode
     * @param message 自定义消息
     */
    public static void throwFail(Integer rCode, String message) {
        throw new ServiceException(rCode, message);
    }

    /**
     * 直接抛出失败异常，抛出 code 码
     *
     * @param message 自定义消息
     */
    public static void throwFail(String message) {
        throwFail(SystemCodeEnum.FAILURE, message);
    }

    public Integer getCode() {
        return this.code;
    }

    public T getData() {
        return this.data;
    }

    public String getMsg() {
        return this.msg;
    }

    public boolean isSuccess() {
        return this.success;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public void setData(T data) {
        this.data = data;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String toString() {
        return "R(code=" + this.getCode() + ", msg=" + this.getMsg() + ", success=" + this.isSuccess() + ", data=" + this.getData() + ")";
    }
}
